package org.ring.common.extension;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @since 2024-10-30 19:10
 */
public class ExtensionLoader<T> {
    private Class<T> type;
    private Map<String,Class> extensionClasses = new HashMap<>();
    private Map<String,T> extensions = new ConcurrentHashMap<>();

    public ExtensionLoader(Class<T> type) {
        this.type = type;
        loadExtensionClass();
    }


    public T getExtension(String name){
        T extension = extensions.get(name);
        if(extension == null){
            //create
            Class cls = extensionClasses.get(name);
            synchronized (cls){
                try {
                    extension = (T)cls.newInstance();
                    extensions.put(name,extension);
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return extension;
    }

    private void loadExtensionClass() {
        //classloader ----> how to find classloader
        ClassLoader classLoader = ExtensionLoader.class.getClassLoader();
        String fileName = "META-INF/extensions/" + type.getName();
        try {
            Enumeration<URL> urls = classLoader.getResources(fileName);
            while (urls.hasMoreElements()){
                URL url = urls.nextElement();
                String path = url.getPath();
                List<String> lines = Files.readAllLines(new File(path).toPath());
                for(String line : lines){
                    String[] pair = line.split("=");
                    String name = pair[0];
                    String implClass = pair[1];
                    Class extensionCls = Class.forName(implClass);
                    extensionClasses.put(name,extensionCls);
                }
            }
        } catch (IOException e) {
            //TODO
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            //TODO
            throw new RuntimeException(e);
        }

    }
}
